// 定义管理蛇的类
export default class Snake {
  element: HTMLElement // 蛇的整体（仅容器）
  // 表示蛇头的元素
  head: HTMLElement
  // 蛇的整体身体节数(包括蛇头)是一个元素div组成的数组
  body: HTMLCollection
  constructor() {
    this.element = document.getElementById('snake') as HTMLElement
    this.head = document.querySelector('.snake > div') as HTMLElement
    this.body = this.element.getElementsByTagName('div')
  }
  // 获取蛇头的坐标
  get X() {
    return this.head.offsetLeft
  }
  get Y() {
    return this.head.offsetTop
  }
  // 设置蛇头的坐标
  set X(value: number) {
    if (value === this.X) return
    // 判断蛇是否撞墙
    if (value < 0 || value > 290) {
      throw new Error('蛇撞墙了！') // 抛出异常
    }
    // 判断是否为“掉头”行为
    if(this.body[1] && (this.body[1] as HTMLElement).offsetLeft === value) {
      if(value > this.X) {
        // 纠正为继续向左移动
        value = this.X - 10
      } else {
        // 纠正为继续向右移动
        value = this.X + 10
      }
    }
    // 先调整身体的位置
    this.moveBody()
    this.head.style.left = value + 'px'
    // 检查蛇头是否撞到身体
    this.checkTouchMe()
  }
  set Y(value: number) {
    if (value === this.Y) return
    if (value < 0 || value > 290) {
      throw new Error('蛇撞墙了！') // 抛出异常
    }
    // 判断是否为“掉头”行为
    if(this.body[1] && (this.body[1] as HTMLElement).offsetTop === value) {
      if(value > this.Y) {
        // 纠正为继续向上移动
        value = this.Y - 10
      } else {
        // 纠正为继续向下移动
        value = this.Y + 10
      }
    }
    // 先调整身体的位置
    this.moveBody()
    this.head.style.top = value + 'px'
    // 检查蛇头是否撞到身体
    this.checkTouchMe()
  }
  // 蛇增加身体的方法
  addBody() {
    // 向蛇的容器中追加一个 div 标签即可
    this.element.insertAdjacentHTML('beforeend', '<div></div>')
  }
  // 移动蛇身体的方法（除了头）
  moveBody() {
    for (let i = this.body.length - 1; i > 0; i--) {
      // 后面一节身体的坐标就是前面一节身体的坐标(除了头部)
      let X = (this.body[i - 1] as HTMLElement).offsetLeft;
      let Y = (this.body[i - 1] as HTMLElement).offsetTop;

      (this.body[i] as HTMLElement).style.left = X + 'px';
      (this.body[i] as HTMLElement).style.top = Y + 'px';
    }
  }
  // 定义一个检查蛇有没有撞到自己的方法
  checkTouchMe() {
    // 原理：获取所有的身体部分的坐标看是否和自己有重叠
    for(let i = 2; i < this.body.length; i++) {
      let bd = this.body[i] as HTMLElement
      // 如果坐标相等就撞到自己了就抛出异常
      if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
        throw new Error("撞到自己了~~");
      }

    }
  }
  // 定义一个游戏结束后重置蛇信息的方法
  resetSnake() {
    // 清除身体仅剩一个头部
    if(this.body.length > 1) {
      let list:HTMLElement[] = Array.from(this.body)
      list.forEach((el: HTMLElement, index: number) => {
        if(index > 0) {
          this.element.removeChild(el)
        }
      });
    }
    // 随机给新蛇头生成位置坐标
    // X 轴和 Y 轴范围均是 0 ~ 290 且值必须能整除 10 才能被 “蛇” 吃到
    this.X = Math.round(Math.random() * 29) * 10
    this.Y = Math.round(Math.random() * 29) * 10
  }
}
